/*
 * Copyright (c) 2019 - 2020 IoT Company of Midea Group.
 *
 * File Name 	    :
 * Description	    : hal ble
 *
 * Version	        : v0.0.1
 * Author			: Moore
 * Date	            : 2020/03/14  refactoring
 * History	        :
 */

#ifndef _MS_HAL_BLE_H_
#define _MS_HAL_BLE_H_

/**
 * !!! please see the config.mk to make sure your chip whether had those function !!!
 * MS_CONFIG_BLE_SUPPORT
 * !!! if not, do not adapter following interfaces
 */

#include "ms_hal.h"

#ifdef __cplusplus
extern "C" {
#endif

#define MS_CONFIG_BLE_SUPPORT
#ifdef MS_CONFIG_BLE_SUPPORT

#define MS_HAL_BLE_HI_WORD(x) ((uint8_t)((x & 0xFF00) >> 8))
#define MS_HAL_BLE_LO_WORD(x) ((uint8_t)(x))

#define MS_HAL_BLE_ADDR_LEN 6

typedef enum {
    // ble stack init
    MS_HAL_BLE_STACK_EVENT_STACK_READY = 0x00, //!< ble stack init success
    MS_HAL_BLE_STACK_EVENT_STACK_STOP,         //!< ble stack stop success
    MS_HAL_BLE_STACK_EVENT_STACK_FAIL,         //!< ble stack init/stop/.. fail

    // ble adv and scan
    MS_HAL_BLE_STACK_EVENT_SCAN_ON = 0x20,  //!< ble scan start
    MS_HAL_BLE_STACK_EVENT_SCAN_OFF,        //!< ble scan stops
    MS_HAL_BLE_STACK_EVENT_ADV_ON,          //!< ble conn advertising start
    MS_HAL_BLE_STACK_EVENT_ADV_OFF,         //!< ble conn advertising stop
    MS_HAL_BLE_STACK_EVENT_NONCONN_ADV_ON,  //!< ble nonconn advertising start
    MS_HAL_BLE_STACK_EVENT_NONCONN_ADV_OFF, //!< ble nonconn advertising stop

    MS_HAL_BLE_STACK_EVENT_EXT_ADV_ON,  //!< ble nonconn advertising start
    MS_HAL_BLE_STACK_EVENT_EXT_ADV_OFF, //!< ble nonconn advertising stop

    // ble connect
    MS_HAL_BLE_STACK_EVENT_DISCONNECTED = 0x40,      //!< ble connected disconnect
    MS_HAL_BLE_STACK_EVENT_CONNECTION_REPORT,        //!< ble connection information above central or perpheral
    MS_HAL_BLE_STACK_EVENT_NOTIFY_REQ,               //!< ble notify data callback  //GATT_EVENT,Master get Ntf data form Slave
    MS_HAL_BLE_STACK_EVENT_INDICATE_REQ,             //!< ble indicate data callback //GATT_REQ_EVENT,Master get Ind data form Slave
    MS_HAL_BLE_STACK_EVENT_DISC_SVC_REPORT,          //!< discovery all service report
    MS_HAL_BLE_STACK_EVENT_DISC_CHAR_REPORT,         //!< discovery all char report
    MS_HAL_BLE_STACK_EVENT_DISC_DESC_REPORT,         //!< discovery all descriptor report
    MS_HAL_BLE_STACK_EVENT_MTU_CHANGED,              //!< MTU changed callback
    MS_HAL_BLE_STACK_EVENT_CONNECT_PARAM_UPDATE_REQ, //!< Connection information

    MS_HAL_BLE_STACK_EVENT_CMP = 0X80,         //!< Complete event start ID, Do not use.
    MS_HAL_BLE_STACK_EVENT_CMP_MTU,            //!< MTU change complete
    MS_HAL_BLE_STACK_EVENT_CMP_SVC_DISC,       //!< discovery service done
    MS_HAL_BLE_STACK_EVENT_CMP_CHAR_DISC,      //!< discovery characteristic done
    MS_HAL_BLE_STACK_EVENT_CMP_DISC_DESC_CHAR, //!< discover characteristic descriptor done
    MS_HAL_BLE_STACK_EVENT_CMP_WRITE_REQ,      //!< write request complete
    MS_HAL_BLE_STACK_EVENT_CMP_WRITE_CMD,      //!< write cmd complete
    MS_HAL_BLE_STACK_EVENT_CMP_NOTIFY,         //!< Notify complete
    MS_HAL_BLE_STACK_EVENT_CMP_INDICATE,       //!< Indicate complete
} ms_hal_ble_stack_event_t;

typedef enum {
    MS_HAL_BLE_ROLE_CENTRAL = 0x00, //!< central role
    MS_HAL_BLE_ROLE_PERIPHERAL,     //!< peripheral role
} ms_hal_ble_role_e;

/**
 * @brief ble gatt msg data struct
 */
typedef struct {
    uint16_t conn_hdl;
    uint16_t att_hdl;
    uint16_t data_len;
    uint8_t *data;
} ms_hal_ble_gatt_msg_t;

/**
 * @brief ble discover server msg struct
 */
typedef struct {
    uint16_t conn_hdl;
    uint16_t start_hdl;
    uint16_t end_hdl;
    uint8_t uuid_len;
    uint8_t *uuid;
} ms_hal_ble_disc_svc_msg_t;

/**
 * @brief ble discover characteristic msg struct
 */
typedef struct {
    uint16_t conn_hdl;
    uint16_t att_hdl;
    uint16_t pointer_hdl;
    uint8_t prop;
    uint8_t uuid_len;
    uint8_t *uuid;
} ms_hal_ble_disc_char_msg_t;

/**
 * @brief ble discover descriptor msg struct
 */
typedef struct {
    uint16_t conn_hdl;
    uint16_t att_hdl;
    uint8_t uuid_len;
    uint8_t *uuid;
} ms_hal_ble_disc_desc_msg_t;

/**
 * @brief ble mtu value changed msg struct
 */
typedef struct {
    uint16_t conn_hdl;
    uint16_t mtu;
} ms_hal_ble_mtu_changed_msg_t;

/**
 * @brief ble connected msg data struct
 */
typedef struct {
    uint16_t conn_hdl;
    uint8_t addr[MS_HAL_BLE_ADDR_LEN];
    uint16_t con_interval;
    uint16_t con_latency;
    uint16_t sup_timeout;
    uint8_t clk_accuracy;
    uint8_t peer_addr_type;
    ms_hal_ble_role_e role;
} ms_hal_ble_connection_msg_t;

/**
 * @brief ble disconnect msg struct
 */
typedef struct {
    uint16_t conn_hdl;
    uint8_t reason;
} ms_hal_ble_disconnect_msg_t;

/**
 * @brief ble connection param data struct
 */
typedef struct {
    uint16_t conn_hdl;
    uint16_t conn_intv_min;
    uint16_t conn_intv_max;
    uint16_t slave_latency;
    uint16_t timeout;
} ms_hal_ble_conn_param_msg_t;

/**
 * @brief ms_hal_ble_stack_msg struct
 */
typedef struct {
    ms_hal_ble_stack_event_t event_type;
    union {
        uint16_t conn_hdl;
        ms_hal_ble_gatt_msg_t gatt_msg;
        ms_hal_ble_disc_svc_msg_t disc_svc_msg;
        ms_hal_ble_disc_char_msg_t disc_char_msg;
        ms_hal_ble_disc_desc_msg_t disc_desc_msg;
        ms_hal_ble_mtu_changed_msg_t mtu_changed_msg;
        ms_hal_ble_connection_msg_t connection_msg;
        ms_hal_ble_disconnect_msg_t disconnect_msg;
        ms_hal_ble_conn_param_msg_t conn_param_msg;
    } param;
} ms_hal_ble_stack_msg_t;

typedef int (*ms_hal_ble_stack_callback_t)(ms_hal_ble_stack_msg_t);

/**
 * @brief hal interface, the point to ms_hal_ble_stack_callback function
 * @param ms_hal_ble_stack_event_t
 * @return int
 */
extern ms_hal_ble_stack_callback_t ms_hal_ble_stack_callback;
/**
 * @brief hal interface, set ble stack callback
 * @param ms_hal_ble_stack_callback_t
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_set_stack_event_register(ms_hal_ble_stack_callback_t event_handler);

/**
 * @brief system interface, get module ble mac
 * @param[in/out] mac
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_get_public_mac_address(uint8_t *p_mac);

/**
 * @brief hal interface, start ble stack
 * @param void
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_stack_start(void);

/**
 * @brief hal interface, stop ble stack
 * @param void
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_stack_stop(void);

/**
 * @brief hal interface, get ble stack status
 * @param void
 * @return on/off, 1:on, 0:off
 */
uint8_t ms_hal_ble_get_stack_status(void);

/**
 * @brief ble adv type.
*/
typedef enum {
    MS_HAL_BLE_ADV_TPYE_IND =
        0x00, ///< Accept all advertising packets except directed advertising packets not addressed to this device. */
    MS_HAL_BLE_ADV_TPYE_DIRECT_IND =
        0x01, ///< Accept advertising packets from devices in the whitelist except directed packets not addressed to this device. */
    MS_HAL_BLE_ADV_TPYE_NONCONN_IND = 0x02, ///< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. */
    MS_HAL_BLE_ADV_TPYE_SCAN_IND = 0x03,    ///< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST.*/
    MS_HAL_BLE_ADV_TPYE_EXT_IND = 0x04,     ///<
    MS_HAL_BLE_AUX_TPYE_ADV_IND = 0x05,     ///<
    MS_HAL_BLE_AUX_TPYE_SYNC_IND = 0x06,    ///<
    MS_HAL_BLE_AUX_TPYE_CHAIN_IND = 0x07,   ///<
} ms_hal_ble_adv_type_e;

typedef struct {
    ms_hal_ble_adv_type_e adv_type; //!< advertising type
    uint32_t adv_intv_min;          //!< Minimum advertising interval (in unit of 625us). Must be greater than 20ms
    uint32_t adv_intv_max;          //!< Maximum advertising interval (in unit of 625us). Must be greater than 20ms
} ms_hal_ble_gap_adv_params;

typedef struct {
    uint16_t adv_len;
    uint8_t *adv_data;
    uint16_t rsp_len;
    uint8_t *rsp_data;
} ms_hal_ble_gap_adv_data;

/**
 * @brief hal interface, start ble advertising
 * @param[in] param: adv param is type and interval
 * @param[in] adv_data: adv data or rsp data is tlv data
 * @return ms_hal_result_t
 * @note 1. if app connect device, please return false.
 *       2. if will use this interface to update adv data, please check whether is support.
 */
uint16_t ms_hal_ble_legacy_adv_start(ms_hal_ble_gap_adv_params *param, ms_hal_ble_gap_adv_data *adv_data);

/**
 * @brief hal interface, update ble advertising
 * @param[in] adv_handle: adv handle
 * @param[in] adv_data: adv data or rsp data is tlv data
 * @return ms_hal_result_t
 * @note 1. if app connect device, please return false.
 *       2. if will use this interface to update adv data, please check whether is support.
 */
ms_hal_result_t ms_hal_ble_legacy_adv_update(uint16_t adv_handle, ms_hal_ble_gap_adv_data *adv_data);

/**
 * @brief hal interface, stop ble advertising
 * @param void
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_adv_stop(uint16_t handle);

/**
 * @brief hal interface, get ble advertising status
 * @param void
 * @return on/off, 1:on, 0:off
 */
uint8_t ms_hal_ble_adv_status(uint16_t handle);

// add ext adv api
typedef struct {
    uint8_t max_ext_event; // set ext adv event num
    uint8_t adv_sid;       // the adv_sid parameter specifies the value to be transmitted subfield of the adi field
    uint16_t adv_prop;     // the adv_prop param describes the type of adv event
    uint32_t adv_intv_min; // Minimum advertising interval (in unit of 625us). Must be greater than 20ms
    uint32_t adv_intv_max; // Maximum advertising interval (in unit of 625us). Must be greater than 20ms
    /**
    //!!!doc write, reference value ,chain adv 根据adv_len 分包,不对adv  operation 设置
    Primary_Advertising_Channel_Map
    Own_Address_Type
    Peer_Address_Type
    Peer_Address
    Advertising_Filter_Policy
    Advertising_TX_Power
    Primary_Advertising_PHY
    Secondary_Advertising_Max_Skip
    Secondary_Advertising_PHY
    Scan_Request_Notification_Enable
    */
} ms_hal_ble_gap_ext_adv_params;

/**
 * @brief hal interface, start & update ble ext advertising
 * @param[in] param: ext adv param
 * @param[in] adv_data: adv data is tlv data
 * @param[in] adv_len:  adv data len
 * @param[in] rsp_date
 * @param[in] rsp_len
 * @return ms_hal_result_t
 */
uint16_t ms_hal_ble_ext_adv_start(ms_hal_ble_gap_ext_adv_params *param, ms_hal_ble_gap_adv_data *adv_data);

/**
 * @brief hal interface, update ext ble advertising
 * @param[in] adv_handle: adv handle
 * @param[in] adv_data: adv data or rsp data is tlv data
 * @return ms_hal_result_t
 * @note 1. if app connect device, please return false.
 *       2. if will use this interface to update adv data, please check whether is support.
 */
ms_hal_result_t ms_hal_ble_ext_adv_update(uint16_t adv_handle, ms_hal_ble_gap_adv_data *adv_data);

/**
 * @brief hal interface, ext adv stop ble advertising
 * @param void
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_ext_adv_stop(uint8_t adv_handle);

/**
 * @brief ble scan filter policy.
*/
typedef enum {
    MS_HAL_BLE_SCAN_FP_ACCEPT_ALL =
        0x00, ///< Accept all advertising packets except directed advertising packets not addressed to this device. */
    MS_HAL_BLE_SCAN_FP_WHITELIST =
        0x01, ///< Accept advertising packets from devices in the whitelist except directed packets not addressed to this device. */
    MS_HAL_BLE_SCAN_FP_ALL_NOT_RESOLVED_DIRECTED =
        0x02, ///< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_ACCEPT_ALL. */
    MS_HAL_BLE_SCAN_FP_WHITELIST_NOT_RESOLVED_DIRECTED =
        0x03, ///< Accept all advertising packets specified in @ref BLE_GAP_SCAN_FP_WHITELIST.*/
} ms_hal_ble_scan_filter_policy_t;

/**
 * @brief BLE ddress Type
 */
typedef enum {
    MS_HAL_BLE_ADDR_TYPE_PUBLIC = 0,                ///< public address
    MS_HAL_BLE_ADDR_TYPE_RANDOM_STATIC = 1,         ///< random static address
    MS_HAL_BLE_ADDR_TYPE_RANDOM_RESOLVABLE = 2,     ///< random resolvable addresss
    MS_HAL_BLE_ADDR_TYPE_RANDOM_NON_RESOLVABLE = 3, ///< random non resolvable address
} ms_hal_ble_addr_type;

/**
 * @brief BLE address structure
*/
typedef struct {
    ms_hal_ble_addr_type addr_type;    ///< address type.
    uint8_t addr[MS_HAL_BLE_ADDR_LEN]; ///< address byte array.
} ms_hal_ble_addr_t;

/**
 * @brief BLE while listing.
*/
typedef struct {
    uint8_t addr_count;         ///< device count
    ms_hal_ble_addr_t *p_addrs; ///< device address's array. Its size is equal to addr_count.
} ms_hal_ble_whitelist_t;

typedef enum {
    MS_HAL_BLE_SCAN_MODE_CLASSIC,
    MS_HAL_BLE_SCAN_MODE_EXT,
    MS_HAL_BLE_SCAN_MODE_CLASSIC_AND_EXT,
} ms_hal_ble_scan_mode_e;

//重复过滤时间是否应用下发，或者多久？
typedef struct {
    bool active;                                   ///< scan active or passive
    bool filter_duplicated;                        ///< Filter duplicated device
    ms_hal_ble_scan_filter_policy_t filter_policy; ///< scan filter policy
    ms_hal_ble_whitelist_t *p_whitelist; ///< Pointer to whitelist, NULL if no whitelist or the current active whitelist is to be used.
    uint16_t scan_intvl;                 ///< Scan interval between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s).
    uint16_t scan_window;                ///< Scan window between 0x0004 and 0x4000 in 0.625ms units (2.5ms to 10.24s).
    ms_hal_ble_scan_mode_e mode;
} ms_hal_ble_scan_params_t;

/**
 * @brief BLE Report Type
 * the report type is for the scanned peers' type. It could be AD type of passive scan or active scan(SCAN_RSP).
 * it was used in structure ble_gap_evt_adv_report_t.
*/
//增加扩展广播类型? 广播网桥？
// MS_HAL_BLE_REPORT_TYPE_SCAN_RSP
typedef enum {
    MS_HAL_BLE_REPORT_TYPE_IND = 0x00,             ///< Type for ADV_IND found (passive)
    MS_HAL_BLE_REPORT_TYPE_DIRECT_IND = 0x01,      ///< Type for ADV_DIRECT_IND found (passive)
    MS_HAL_BLE_REPORT_TYPE_SCAN_IND = 0x02,        ///< Type for ADV_SCAN_IND found (passive)
    MS_HAL_BLE_REPORT_TYPE_NONCONN_IND = 0x03,     ///< Type for ADV_NONCONN_IND found (passive)
    MS_HAL_BLE_REPORT_TYPE_SCAN_RSP = 0x04,        ///< Type for SCAN_RSP found (active)
    MS_HAL_BLE_REPORT_TYPE_EXT_ADV_IND = 0x05,     ///< Type for ext Connectable found
    MS_HAL_BLE_REPORT_TYPE_EXT_SCAN_IND = 0x06,    ///< Type for ext Scanable found
    MS_HAL_BLE_REPORT_TYPE_EXT_NONCONN_IND = 0x07, ///< Type for ext Nonconnectable and Non-scanable found
    MS_HAL_BLE_REPORT_TYPE_EXT_SCAN_RSP = 0x08,    ///< Type for ext AUX_SCAN_RSP found (active)
} ms_hal_ble_report_type;
//增ext 扩展广播tpye
typedef struct {
    ms_hal_ble_report_type type; ///< report ad type
    ms_hal_ble_addr_t peer_addr; ///< peer addr
    int8_t tx_pwr;               ///< TX power (in dBm)
    int8_t rssi;                 ///< rssi
    uint16_t len;                ///< data len
    uint8_t *data;               ///< data
} ms_hal_ble_scan_t;

// scan callback
typedef void (*ms_hal_ble_scan_callback_t)(ms_hal_ble_scan_t *data);

/**
 * @brief hal interface, start ble scan
 * @param ms_hal_ble_scan_params_t
 * @param ms_hal_ble_scan_callback_t
 * @return ms_hal_result_t
 */
//增加 分三种扫描模式；经典扫描模式 扩展扫描模式 经典&扩展模式
ms_hal_result_t ms_hal_ble_scan_start(ms_hal_ble_scan_params_t *params, ms_hal_ble_scan_callback_t function);

/**
 * @brief hal interface, stop ble scan
 * @param void
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_scan_stop(void);

/**
 * @brief hal interface, get ble scan status
 * @param void
 * @return on/off, on:1, off:0
 */
uint8_t ms_hal_ble_scan_status(void);

/**
 * @brief hal interface, get ble gap connect status
 * @param [in] conn_hdl 链路句柄
 * @return IsConnect?, 1:had connected, 0:not connect
 */
uint8_t ms_hal_ble_gap_connect_status(uint16_t conn_hdl);

/**
 * @brief hal interface, set ble gap to disconnect
 * @param [in] conn_hdl 链路句柄
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_gap_disconnect(uint16_t conn_hdl);

/**
 * @brief hal interface, ms_hal_ble_exchange_mtu
 * @param[in] conn_hdl
 * @param[in] mtu
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_exchange_mtu(uint16_t conn_hdl, uint16_t mtu);

/**
 * @brief hal interface, get ble mtu value
 * @param [in] conn_hdl 链路句柄
 * @return mtu_value
 */
uint16_t ms_hal_ble_mtu_get(uint16_t conn_hdl);

// UUID Service
// service +characteristic +charc_user_description +client_charc_config

/**
 * \ingroup     GATT_ATTRIBUTE
 */
#define MS_BLE_GATT_UUID_PRIMARY_SERVICE 0x2800   /**<  GATT Primary Service Declaration. */
#define MS_BLE_GATT_UUID_SECONDARY_SERVICE 0x2801 /**<  GATT Secondary Service Declaration. */
#define MS_BLE_GATT_UUID_INCLUDE 0x2802           /**<  GATT Include Declaration. */
#define MS_BLE_GATT_UUID_CHARACTERISTIC 0x2803    /**<  GATT Characteristic Declaration. */

#define MS_BLE_GATT_UUID_CHAR_EXTENDED_PROP 0x2900                    /**<  Characteristic Extended Properties. */
#define MS_BLE_GATT_UUID_CHAR_USER_DESCR 0x2901                       /**<  Characteristic User Description. */
#define MS_BLE_GATT_UUID_CHAR_CLIENT_CONFIG 0x2902                    /**<  Client Characteristic Configuration. */
#define MS_BLE_GATT_UUID_CHAR_SERVER_CONFIG 0x2903                    /**<  Server Characteristic Configuration. */
#define MS_BLE_GATT_UUID_CHAR_FORMAT 0x2904                           /**<  Characteristic Presentation Format. */
#define MS_BLE_GATT_UUID_CHAR_AGGR_FORMAT 0x2905                      /**<  Characteristic Aggregate Format. */
#define MS_BLE_GATT_UUID_CHAR_VALID_RANGE 0x2906                      /**<  Valid Range. */
#define MS_BLE_GATT_UUID_CHAR_EXTERNAL_REPORT_REFERENCE 0x2907        /**<  External Report Reference. */
#define MS_BLE_GATT_UUID_CHAR_REPORT_REFERENCE 0x2908                 /**<  Report Reference. */
#define MS_BLE_GATT_UUID_CHAR_DESCRIPTOR_NUM_OF_DIGITALS 0x2909       /**<  Number of Digitals. */
#define MS_BLE_GATT_UUID_CHAR_DESCRIPTOR_VALUE_TRIGGER_SETTING 0x290A /**<  Value Trigger Setting. */
#define MS_BLE_GATT_UUID_CHAR_SENSING_CONFIGURATION 0x290B            /**<  Environmental Sensing Configuration. */
#define MS_BLE_GATT_UUID_CHAR_SENSING_MEASUREMENT 0x290C              /**<  Environmental Sensing Measurement. */
#define MS_BLE_GATT_UUID_CHAR_SENSING_TRIGGER_SETTING 0x290D          /**<  Environmental Sensing Trigger Setting. */
#define MS_BLE_GATT_UUID_CHAR_DESCRIPTOR_TIME_TRIGGER_SETTING 0x290E  /**<  Time Trigger Setting. */

#define MS_HAL_BLE_ATTRIB_CHAR_PROP_NONE 0x00
#define MS_HAL_BLE_ATTRIB_CHAR_PROP_BROADCAST 0x01
#define MS_HAL_BLE_ATTRIB_CHAR_PROP_READ 0x02
#define MS_HAL_BLE_ATTRIB_CHAR_PROP_WRITE_NO_RSP 0x04
#define MS_HAL_BLE_ATTRIB_CHAR_PROP_WRITE 0x08
#define MS_HAL_BLE_ATTRIB_CHAR_PROP_NOTIFY 0x10
#define MS_HAL_BLE_ATTRIB_CHAR_PROP_INDICATE 0x20
#define MS_HAL_BLE_ATTRIB_CHAR_PROP_WRITE_AUTHEN_SIGNED 0x40
#define MS_HAL_BLE_ATTRIB_CHAR_PROP_EXT_PROP 0x80

#define MS_HAL_BLE_ATTRIB_PERM_NONE 0x00
#define MS_HAL_BLE_ATTRIB_PERM_READ 0x01
#define MS_HAL_BLE_ATTRIB_PERM_WRITE 0x02
//

typedef enum _ms_hal_ble_uuid_size_ {
    ENUM_MS_HAL_BLE_UUID_SIZE_NULL = 0,
    ENUM_MS_HAL_BLE_UUID_SIZE_16_BIT = 2,
    ENUM_MS_HAL_BLE_UUID_SIZE_128_BIT = 16,
} ms_hal_ble_uuid_size_t;

typedef enum _ms_hal_ble_attrib_type_ {
    ENUM_MS_HAL_BLE_ATTRIB_TYPE_SERVICE = MS_BLE_GATT_UUID_PRIMARY_SERVICE,
    ENUM_MS_HAL_BLE_ATTRIB_TYPE_CHAR = MS_BLE_GATT_UUID_CHARACTERISTIC,
    ENUM_MS_HAL_BLE_ATTRIB_TYPE_CHAR_USER_DESCR = MS_BLE_GATT_UUID_CHAR_USER_DESCR,
    ENUM_MS_HAL_BLE_ATTRIB_TYPE_CHAR_CLIENT_CONFIG = MS_BLE_GATT_UUID_CHAR_CLIENT_CONFIG,
} ms_hal_ble_attrib_type_t;

typedef void (*ms_hal_ble_service_null_cb)(void);
typedef void (*ms_hal_ble_service_read_cb)(uint8_t *data, uint16_t *size);
typedef void (*ms_hal_ble_service_write_cb)(uint8_t *data, uint16_t size);
typedef void (*ms_hal_ble_service_cccd_cb)(uint16_t value);

typedef union _ms_hal_ble_attrib_callback_ {
    ms_hal_ble_service_null_cb null_cb;
    ms_hal_ble_service_read_cb read_cb;
    ms_hal_ble_service_write_cb write_cb;
} ms_hal_ble_attrib_callback_t;

typedef struct {
    ms_hal_ble_uuid_size_t uuid_size;
    uint8_t uuid[ENUM_MS_HAL_BLE_UUID_SIZE_128_BIT]; /** service UUID */
} ms_hal_ble_service_para_t;

typedef struct {
    ms_hal_ble_uuid_size_t uuid_size;
    uint8_t uuid[ENUM_MS_HAL_BLE_UUID_SIZE_128_BIT]; /** service UUID */
    uint8_t property;
    uint8_t permission;
    ms_hal_ble_attrib_callback_t callback;
} ms_hal_ble_charact_para_t;

typedef struct {
    // Characteristic User Description
    uint8_t permission;
    uint16_t value_len;
    uint8_t *value_context;
} ms_hal_ble_charact_user_desc_para_t;

typedef struct {
    // Client Characteristic Configuration
    uint8_t permission;
    ms_hal_ble_service_cccd_cb
        callback; /* Only need to inform the application of the cccd value, the application does not save the cccd value */
} ms_hal_ble_client_charact_config_para_t;

/**
 * att_type is service/characteristic/characteristic_value/char_client_config/char_user_descr, see ms_hal_ble_attrib_type_t
 * uuid_type : see ms_hal_ble_uuid_size_t
 * uuid : 16bit/128bit uuid
 * prop : if att_type is characteristic, you need to choose MS_HAL_BLE_ATTRIB_CHAR_PROP_XXX
 *        if att_type is characteristic_value, you need to check the last characteristic->prop
 * value_len : len of value_context
 * value_context : normal for char_user_descr
 * perm : you need to choose MS_HAL_BLE_ATTRIB_PERM_XXX
 */
typedef int ms_hal_ble_gatts_attr_handle_t; // todo

typedef struct _ms_hal_ble_service_attrib_ {
    ms_hal_ble_attrib_type_t att_type;
    union {
        ms_hal_ble_service_para_t service_para;
        ms_hal_ble_charact_para_t charact_para;
        ms_hal_ble_charact_user_desc_para_t user_desc_para;
        ms_hal_ble_client_charact_config_para_t ccc_para;
    };
    // output,need to adapt;
    // used for ms_hal_ble_gatt_data_send
    ms_hal_ble_gatts_attr_handle_t handle;
} ms_hal_ble_service_attrib_t;

typedef struct {
    uint16_t attr_count;
    uint16_t charact_count;
    ms_hal_ble_service_attrib_t *attrs;
} ms_hal_ble_service_t;

/**
 * @brief hal interface, add ble gatt service
 * @param[in] handle 服务句柄
 * @param[in] *service 服务
 * @param[in] attrib_database_count 属性个数
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_gatt_service_add(ms_hal_ble_service_t *service);

/**
 * @brief hal interface, send ble gatt data
 * @param[in] handle 服务句柄
 * @param[in] attrib_offset 属性偏移
 * @param[in] data 数据
 * @param[in] len 数据长度
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_gatt_data_send(uint16_t conn_hdl, ms_hal_ble_gatts_attr_handle_t *handle, uint8_t *data, uint16_t len);

typedef struct {
    uint16_t conn_intv_min;
    uint16_t conn_intv_max;
    uint16_t slave_latency;
    uint16_t timeout;
} ms_hal_ble_conn_param_t;

/**
 * @brief hal interface, ms_hal_ble_discovery_all_service
 * @param[in] conn_hdl
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_discovery_all_service(uint16_t conn_hdl);

/*!
 * @brief hal interface, ms_hal_ble_discovery_all_char
 * @param conn_hdl
 * @param start_hdl
 * @param end_hdl
 * @return  ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_discovery_all_char(uint16_t conn_hdl, uint16_t start_hdl, uint16_t end_hdl);

/**
 * @brief hal interface, ms_hal_ble_discovery_all_descriptor
 * @param[in] conn_hdl
 * @param[in] start_hdl
 * @param[in] end_hdl
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_discovery_all_descriptor(uint16_t conn_hdl, uint16_t start_hdl, uint16_t end_hdl);

/**
 * @brief hal interface, ms_hal_ble_set_cccd
 * @param[in] cccd_value  notify：0x0001 indicate: 0x0002
 * @param[in] conn_hdl    链路句柄
 * @param[in] att_handle  属性句柄
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_set_cccd(uint16_t cccd_value, uint16_t conn_hdl, uint16_t att_handle);

//增加read cccd 的接口
/**
 * @brief hal interface, ms_hal_ble_gatt_write
 * @param[in] type        0：write request 1: write cmd
 * @param[in] conn_hdl    链路句柄
 * @param[in] att_handle  属性句柄
 * @param[in] len  数据长度
 * @param[in] data 数据内容
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_gatt_write(uint8_t type, uint16_t conn_hdl, uint16_t att_handle, uint16_t len, uint8_t *data);

/**
 * @brief hal interface, ms_hal_ble_conn_start
 * @param[in] target          对端Address
 * @param[in] own_addr_type   自身Address类型。GAPM_STATIC_ADDR、GAPM_GEN_RSLV_ADDR、GAPM_GEN_NON_RSLV_ADDR
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_conn_start(ms_hal_ble_conn_param_t *param, ms_hal_ble_addr_t *target);

/**
 * @brief hal interface, ms_hal_ble_conn_stop
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_conn_stop(void);

/**
 * @brief hal interface, ms_hal_ble_send_param_update_cfm
 * @param[in] conn_hdl        链路句柄
 * @param[in] accept          true；接受参数更新 false:拒绝参数更新
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_send_param_update_cfm(uint16_t conn_hdl, bool accept);

/**
 * @brief hal interface, ms_hal_ble_set_device_name
 * @param[in] name         设备名
 * @param[in] len          名字长度
 * @return ms_hal_result_t
 */
ms_hal_result_t ms_hal_ble_set_device_name(uint8_t *name, uint8_t len);

#endif /* MS_CONFIG_BLE_SUPPORT */

#ifdef __cplusplus
}
#endif

#endif //__MS_HAL_BLE_H__
